############################################################################
#
# DIM - A Direct Interaction Manager for SAGE
# Copyright (C) 2007 Electronic Visualization Laboratory,
# University of Illinois at Chicago
#
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following disclaimer
#    in the documentation and/or other materials provided with the distribution.
#  * Neither the name of the University of Illinois at Chicago nor
#    the names of its contributors may be used to endorse or promote
#    products derived from this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
#
# Author: Hyejung Hur
#        
############################################################################

from globals import *
import traceback as tb
import sys
from overlays.app import App


class PatternAnalyzer:
	def __init__(self):
		self.cmd_list = [] 
		self._expectCmd = EVT_ANAL_NO_PATTERN
		self._toSec = None

		self.direction =0
		self.expectWidth =0
		self.expectHeight =0
		self.expectX =0
		self.expectY =0
		self.appliedList = []

	def clear(self): 
		self._expectCmd = EVT_ANAL_NO_PATTERN
		del self.cmd_list
		self.cmd_list = [] 
		del self.appliedList 
		self.appliedList = []

	def register(self, cmd, app): 
		del self.appliedList 
		self.appliedList = []
                if cmd == EVT_ANAL_TO_SESSION :
			self._expectCmd = cmd
			self._toSec = app.section  
			del self.cmd_list
			self.cmd_list = [] 
			self.appliedList.append(app.getId())
			#print "analyzer: session set"
                else :
			# bounds: left, right, top, bottom
			l= cmd, app.getId(), app
			self.cmd_list.append(l)
			if len(self.cmd_list) > 1 :
				self.__analyze()

	def getAction(self, app): 
                if app == None : 
		    return self._expectCmd

		if app.getId() in self.appliedList : 
			#print "it is already applied"
			return EVT_ANAL_NO_PATTERN

		# check wether app is already applied new action ot not
		if self._expectCmd != EVT_ANAL_NO_PATTERN :
			self.appliedList.append(app.getId())
		return self._expectCmd

	def getSection(self): 
		return self._toSec

	def getMove(self, app): 
		#print "get move"
		width = app.right - app.left 
		height = app.top- app.bottom 
		x, y = self._getNewPosition(app, width, height) 
		x = x - self.left 
		y = y - self.bottom 
		# return deltax, delta y
		return [x, y]

	def getMoveResize(self, app):
		#print "get move resize"
		# return left, right, top, bottom
		width, height = self._getNewSize(app)
		x, y = self._getNewPosition(app, width, height) 
		right = x + width
		top = y + height
		return [x, right, top, y]

	def getResize(self, app):
		#print "resize"
		width, height = self._getNewSize(app)
		right = app.left + width
		top = app.bottom + height
		return [app.left, right, top, app.bottom]

	def _getNewSize(self, app):
		# return left, right, top, bottom
		# aspect_ratio = x / y
		a = 0
		awidth = app.aspectRatio * self.expectHeight 
		aheight = 0
		if awidth > self.expectWidth :
			awidth = self.expectWidth
			aheight = 1.0 * awidth / app.aspectRatio 
			a = awidth * aheight 

		b = 0 		
		bwidth = 0
		bheight = 1.0 * self.expectWidth / app.aspectRatio 
		if bheight > self.expectHeight :
			bheight = self.expectHeight
			bwidth = app.aspectRatio * bheight
			b = bwidth * bheight 

		if a > b : 
			return [awidth, aheight]

		return [bwidth, bheight]


	def _getNewPosition(self, app, width, height): 
		# need to check section.
                x = 0
                y = 0
		if self.direction == EVT_ANAL_X_LEFT_DIR :
			x = self.expectX - width  -10
			y = self.expectY
			if (x + width) < 30 :
				a = self.cmd_list[0] 
				x = a[2].left 
				y -= self.expectHeight - 10 
			self.expectX = x
			self.expectY = y 
		elif self.direction == EVT_ANAL_X_RIGHT_DIR :
			x = self.expectX + 10
			y = self.expectY
			if x >= app.section.bounds.right :
				a = self.cmd_list[0] 
				x = a[2].left 
				y -= self.expectHeight - 10 
			self.expectX = x + width
			self.expectY = y 
		elif self.direction == EVT_ANAL_Y_UP_DIR : 
			x = self.expectX 
			y = self.expectY + 10
			if (y + height) >= app.section.bounds.top :
				a = self.cmd_list[0] 
				x += self.expectWidth + 10
				y = a[2].bottom 
			self.expectX = x
			self.expectY = y + height
		elif self.direction == EVT_ANAL_Y_DOWN_DIR : 
			x = self.expectX 
			y = self.expectY - height - 10
			if y < 0 :
				a = self.cmd_list[0] 
				x += self.expectWidth + 10
				y = a[2].bottom 
			self.expectX = x
			self.expectY = y
		return [x, y]


	def __analyze(self): 
		# by default... 
		numList = len(self.cmd_list)

		a_idx = 0 
		remove_list = []
		add_list = []
		for a in self.cmd_list : 
			cmd =a[0] 
			wId = a[1] 
			if cmd == EVT_ANAL_DRAG :
				b_idx = 0 
				# find resize with same id
				for i in range(numList) : 
					b_idx = numList - i -1
					if a_idx == b_idx : break 

					b = self.cmd_list[b_idx]
					if b[1] == wId :
						if b[0] == EVT_ANAL_DRAG :
							# remove first one
							remove_list.append(a)
						else : 
							# resize
							l= EVT_ANAL_DRAG_RESIZE, wId, b[2] 
							add_list.append(l)
							remove_list.append(a)
							remove_list.append(b)
			else : 
				# resize
				b_idx = 0 
				for i in range(numList) : 
					b_idx = numList - i -1
					if a_idx == b_idx : break 

					b = self.cmd_list[b_idx]
					if b[1] == wId :
						if b[0] == EVT_ANAL_DRAG :
							# remove first one
							l= EVT_ANAL_DRAG_RESIZE, wId, b[2] 
							add_list.append(l)
							remove_list.append(a)
							remove_list.append(b)
						else : 
							# resize
							remove_list.append(a)
			a_idx += 1 
		for r in remove_list : 
			self.cmd_list.remove(r)
		for a in add_list : 
			self.cmd_list.append(a)

		numList = len(self.cmd_list)
		if numList > 2 :
			# remove 
			diff = numList -2 
			for i in range(diff) :
				self.cmd_list.pop(i)

		#print "final<analyzer>-----" 
		#for a in self.cmd_list:
		#	print a[0], a[1]
		#print "-----" 
		
		# 1. if cmd_list has one, then... set cmd and quick
		if numList == 1 :
			#print "merged, wait for another action"
			return

		# compare cmd 
		a = self.cmd_list[0]
		b = self.cmd_list[1]
		if a[0] == b[0] : 
			self._expectCmd = a[0] 
			self.appliedList.append(a[1])
			self.appliedList.append(b[1])
			# analyze according to command.
			#print "do someting, find same behavior"
			if self._expectCmd == EVT_ANAL_DRAG_RESIZE:
				self.__positionAnalyze()
				self.__sizeAnalyze()
			elif self._expectCmd == EVT_ANAL_DRAG :
				self.__positionAnalyze()
				self.__sizeAnalyze()
			if self._expectCmd == EVT_ANAL_RESIZE:
				self.__sizeAnalyze()
		else : 
			# do more... intelligent
			#print " checking pattern"
			if self.__hasPattern() == True :
				self._expectCmd = EVT_ANAL_DRAG_RESIZE 
				self.appliedList.append(a[1])
				self.appliedList.append(b[1])
				self.__positionAnalyze()
				self.__sizeAnalyze()
			else :
				self._expect_Cmd = EVT_ANAL_NO_PATTERN 
				if not (a[0] == EVT_ANAL_DRAG_RESIZE or b[0] == EVT_ANAL_DRAG_RESIZE) :
					#print "ignore first action"
					self.cmd_list.pop(0)
				#else :
				#	print "wait for another action"


	def __positionAnalyze(self):
		a = self.cmd_list[0]
		b = self.cmd_list[1]
		aapp = a[2]
		bapp = b[2]

		# left, right, top, bottom
		abound = [aapp.left, aapp.right, aapp.top, aapp.bottom]
		bbound = [bapp.left, bapp.right, bapp.top, bapp.bottom]

		# find direction 
		# check overlap
		# x direction
		width = 0
		left = bbound[0]
		#print "1", abound, bbound
		if abound[0] > left and abound[0] < bbound[1] :
			if abound[1] <= bbound[1] : 
				width =  abound[1]  - abound[0]
			else : 
				width =  bbound[1]  - abound[0]
		elif abound[0] <= left and abound[1] > left:
			if abound[1] <= bbound[1] : 
				width =  abound[1]  - left
			else : 
				width =  bbound[1]  - left
			
		height = 0
		bottom = bbound[3]
		if abound[3] > bottom and abound[3] < bbound[2] :
			if abound[2] <= bbound[2] : 
				height =  abound[2]  - abound[3]
			else : 
				height =  bbound[2]  - abound[3]
		elif abound[3] <= bottom and abound[2] > bottom:
			if abound[2] <= bbound[2] : 
				height =  abound[2]  - bottom
			else : 
				height =  bbound[2]  - bottom

		if width == 0 and height == 0 : 
			self._expectCmd = EVT_ANAL_NO_PATTERN
			self.cmd_list.pop(0)
			return
			
		#print "width = ",width, " height= " , height 
		width = 1.0 * width / (abound[1] - abound[0])
		height = 1.0 * height / (abound[2] - abound[3])


		if width < height :
			if abound[0] < left : 
				self.direction = EVT_ANAL_X_RIGHT_DIR 
				if abound[3] < bottom : 
					self.expectY = abound[3]  		
				else : 
					self.expectY = bottom  		
				self.expectX = bbound[1]     		
			else :
				self.direction = EVT_ANAL_X_LEFT_DIR 
				if abound[3] < bottom : 
					self.expectY = abound[3]  		
				else : 
					self.expectY = bottom  		
				self.expectX = bbound[0]     		
		else :
			if abound[3] < bottom : 
				self.direction = EVT_ANAL_Y_UP_DIR 
				# next one should be above : bottom
				if abound[0] < left : 
					self.expectX = abound[0]  		
				else : 
					self.expectX = left  		
				self.expectY = bbound[2]     		
			else :
				self.direction = EVT_ANAL_Y_DOWN_DIR 
				# next one should be under  : top 
				if abound[0] < left : 
					self.expectX = abound[0]  		
				else : 
					self.expectX = left  		
				self.expectY = bbound[3]     		
			
		#print "direction: ",  self.direction, " width =" , width, " height =", height
		#print "next position: ",  self.expectX, self.expectY


	def __sizeAnalyze(self):
		a = self.cmd_list[0]
		b = self.cmd_list[1]
		aapp = a[2]
		bapp = b[2]

		# left, right, top, bottom
		abound = [aapp.left, aapp.right, aapp.top, aapp.bottom]
		bbound = [bapp.left, bapp.right, bapp.top, bapp.bottom]

		awidth = abound[1] - abound[0]
		aheight = abound[2] - abound[3]
		bwidth = bbound[1] - bbound[0]
		bheight = bbound[2] - bbound[3]
		if awidth > bwidth : 
			self.expectWidth = awidth
		else :
			self.expectWidth = bwidth

		if aheight > bheight : 
			self.expectHeight = aheight
		else :
			self.expectHeight = bheight

		#print "width =", self.expectWidth, " height =", self.expectHeight
		#print "(", awidth, aheight, ")" 


	def __hasPattern(self):
		a = self.cmd_list[0]
		b = self.cmd_list[1]
		aapp = a[2]
		bapp = b[2]

		a = 1.0 * (aapp.right - aapp.left) * (aapp.top - aapp.bottom)
		b = 1.0 * (bapp.right - bapp.left) * (bapp.top - bapp.bottom)

		a = a/b
		#print "pattern1", a
		if a < 0.6 or a > 1.4:
			return False

		# left, right, top, bottom
		abound = [aapp.left, aapp.right, aapp.top, aapp.bottom]
		bbound = [bapp.left, bapp.right, bapp.top, bapp.bottom]
		#print abound, bbound

		# find direction 
		# check overlap
		# x direction
		width = 0
		left = bbound[0]
		if abound[0] > left and abound[0] < bbound[1] :
			if abound[1] <= bbound[1] : 
				width =  abound[1]  - abound[0]
			else : 
				width =  bbound[1]  - abound[0]
		elif abound[0] <= left and abound[1] > left:
			if abound[1] <= bbound[1] : 
				width =  abound[1]  - left
			else : 
				width =  bbound[1]  - left
			
		height = 0
		bottom = bbound[3]
		if abound[3] > bottom and abound[3] < bbound[2] :
			if abound[2] <= bbound[2] : 
				height =  abound[2]  - abound[3]
			else : 
				height =  bbound[2]  - abound[3]
		elif abound[3] <= bottom and abound[2] > bottom:
			if abound[2] <= bbound[2] : 
				height =  abound[2]  - bottom
			else : 
				height =  bbound[2]  - bottom

		width = 1.0 * width / (abound[1] - abound[0])
		height = 1.0 * height / (abound[2] - abound[3])

		#print "pattern2-", width, height 
		if width > 0.8 or height > 0.8 : 
			return True

		return False
